package org.example.tx;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.tx.acl.AclService;
import org.example.tx.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
@Slf4j
public class TxService {

    @Autowired
    private UserService userService;

    @Autowired
    private AclService aclService;

    @Resource
    private PlatformTransactionManager transactionManager1;

    @Resource
    private PlatformTransactionManager transactionManager2;

    public void update1() {
        userService.update(1001, true);
    }

    @Transactional(transactionManager = "transactionManager1")
    public void update2() {
        userService.update(1001, false);
        aclService.update(1);
    }

    public void update3() {
        DefaultTransactionDefinition def1 = new DefaultTransactionDefinition();
        def1.setName("user-update");
        TransactionStatus ts1 = transactionManager1.getTransaction(def1);

        DefaultTransactionDefinition def2 = new DefaultTransactionDefinition();
        def2.setName("acl-update");
        TransactionStatus ts2 = transactionManager2.getTransaction(def2);

        RuntimeException error = null;

        try {
            userService.update(1001, false);
        } catch (RuntimeException e1) {
            error = e1;
        }

        if (error == null) {
            try {
                aclService.update(1);
            } catch (RuntimeException e2) {
                error = e2;
            }
        }

        if (error != null) {
            transactionManager2.rollback(ts2);
            transactionManager1.rollback(ts1);
            throw error;
        } else {
            transactionManager2.commit(ts2);
            transactionManager1.commit(ts1);
        }
    }
}
